﻿// MyProject.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
//公众号：程序员速成 ，内含一辈子都让你感激自己的优质视频教程，欢迎关注

#include <iostream>
#include <thread>


#ifdef _DEBUG   //只在Debug（调试）模式下
#ifndef DEBUG_NEW
#define DEBUG_NEW new(_NORMAL_BLOCK,__FILE__,__LINE__) //重新定义new运算符
#define new DEBUG_NEW
#endif
#endif

//#include <boost/type_index.hpp>
using namespace std;
//#pragma warning(disable : 4996) 

namespace _nmsp1
{
	
	//图像显示类
	class Image
	{
	public:
		//根据pData(缓冲区）中的内容以及iDataLen所指示的缓冲区的长度，将这些数据显示出来
		void draw(const char* pfilename)
		{
			int iLen = 0;
			char* pData = parsefile(pfilename, iLen);
			if (iLen > 0)
			{
				cout << "显示pData所指向的缓冲区中的图像数据。" << endl;
				//....
				delete pData; //模拟代码中因为pData的内存是new出来的，所以这里需要释放该内存
			}
		}
		virtual ~Image() {} //做父类时析构函数应该为虚函数
	private:
		//根据文件名分析文件内容，每个子类因为图像文件格式不同，会有不同的读取和处理代码
		virtual char* parsefile(const char* pfilename, int& iLen) = 0;
	};

	//处理png格式图像文件的显示
	class Image_png :public Image
	{
	private:
		//读取png文件内容并进行解析，最终整理成统一的二进制数据格式返回
		virtual char* parsefile(const char* pfilename, int& iLen)
		{
			//以下是模拟代码，模拟从图像文件中读取到了数据，最终转换成了100个字节的数据格式（事先约定好的格式规范）并返回
			cout << "开始分析png文件中的数据并将分析结果放到pData中。";
			iLen = 100;
			char* presult = new char[iLen];
			//...
			return presult;
		}
	};
	//处理jpg格式图像文件的显示
	class Image_jpg :public Image
	{
	private:
		virtual char* parsefile(const char* pfilename, int& iLen)
		{
			cout << "开始分析jpg文件中的数据并将分析结果放到pData中。";
			//......
		}
	};
	//处理jpg格式图像文件的显示
	class Image_bmp :public Image
	{
	private:
		virtual char* parsefile(const char* pfilename, int& iLen)
		{
			cout << "开始分析bmp文件中的数据并将分析结果放到pData中。";
			//......
		}
	};
}
namespace _nmsp2
{
	//操作系统类型相关类
	class ImageOS
	{
	public:
		virtual void draw(char* pData, int iLen) = 0;
		virtual ~ImageOS() {} //做父类时析构函数应该为虚函数
	};
	//Windows操作系统
	class ImageOS_Windows :public ImageOS
	{
	public:
		virtual void draw(char* pData, int iLen)
		{
			cout << "在Windows操作系统下显示pData所指向的缓冲区中的图像数据。" << endl;
			//...具体处理代码略
		}
	};
	//Linux操作系统
	class ImageOS_Linux :public ImageOS
	{
	public:
		virtual void draw(char* pData, int iLen)
		{
			cout << "在Linux操作系统下显示pData所指向的缓冲区中的图像数据。" << endl;
			//...具体处理代码略
		}
	};
	//Mac操作系统
	class ImageOS_Mac :public ImageOS
	{
	public:
		virtual void draw(char* pData, int iLen)
		{
			cout << "在Mac操作系统下显示pData所指向的缓冲区中的图像数据。" << endl;
			//...具体处理代码略
		}
	};
	//----------------------------
	//图像文件格式相关类
	class ImageFormat
	{
	public:
		ImageFormat(ImageOS* pimgos) :m_pImgOS(pimgos) {} //构造函数
		virtual void parsefile(const char* pfilename) = 0; //根据文件名分析文件内容，每个子类因为图像文件格式不同，会有不同的读取和处理代码
		virtual ~ImageFormat() {} //做父类时析构函数应该为虚函数
	protected:
		ImageOS* m_pImgOS; //委托
	};
	//png格式的图像文件
	class Image_png :public ImageFormat
	{
	public:
		Image_png(ImageOS* pimgos) :ImageFormat(pimgos) {} //构造函数
		virtual void parsefile(const char* pfilename)
		{
			cout << "开始分析png文件中的数据并将分析结果放到pData中。";
			int iLen = 100;
			char* presult = new char[iLen];
			m_pImgOS->draw(presult, iLen);

			//释放资源
			delete presult;
		}
	};
	//jpg格式的图像文件
	class Image_jpg :public ImageFormat
	{
	public:
		Image_jpg(ImageOS* pimgos) :ImageFormat(pimgos) {} //构造函数
		virtual void parsefile(const char* pfilename)
		{
			cout << "开始分析jpg文件中的数据并将分析结果放到pData中。";
			//......			
		}
	};
	//bmp格式的图像文件
	class Image_bmp :public ImageFormat
	{
	public:
		Image_bmp(ImageOS* pimgos) :ImageFormat(pimgos) {} //构造函数
		virtual void parsefile(const char* pfilename)
		{
			cout << "开始分析bmp文件中的数据并将分析结果放到pData中。";
			//......			
		}
	};
}

int main()
{
	_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);//程序退出时检测内存泄漏并显示到“输出”窗口

	

	//第16章 桥接（Bridge）模式：桥梁模式（桥模式），结构型模式。
	//解决的问题：根据单一职责原则，在一个类中，不要做太多事情，如果事情很多，尽量拆分到多个类中去，然后在
	  //一个类中包含指向另外一个类对象的指针，当需要执行另外一个类中的动作时，用指针直接去调用另外一个类的成员函数。
	  // 
	//（1）一个传统的继承范例导致子类数量爆炸式增长
	//图像文件格式：png,jpg,bmp等

	//（2）将类与类之间的继承关系改为委托关系
	//类与类之间：继承、组合（委托）；
	//文件格式：png、jpg、bmp。 操作系统类型：Windows、Linux、Mac。
	//说明：a)parsefile()其实现代码与具体操作系统类型无关。  b)：draw()：不同的操作系统，用于显示pData的实现代码不同。

	//（3）引入桥接（Bridge）模式
	//不同维度的独立变化，才是能够顺利使用桥接模式的前提。
	//定义：将抽象部分与它的实现部分分离，使他们都可以独立地变化和扩展。
	//a)抽象部分：一般指业务功能，比如ImageFormat类。
	//b)实现部分：一般指具体平台实现，比如ImageOS类。
	//角色
	//(a)Abstraction（抽象部分相关接口）：ImageFormat类
	//(b)RefinedAbstraction（扩充抽象部分接口）：Image_png、Image_jpg、Image_bmp类。
	//(c)Implementor（实现部分相关接口）：ImageOS类
	//(d)ConcreteImplementor（实现部分具体类）：ImageOS_Windows、ImageOS_Linux、ImageOS_Mac类。
	//单一职责原则，开闭原则，组合复用原则，依赖倒置原则。






	/*
	_nmsp1::Image* pImg = new _nmsp1::Image_png();
	pImg->draw("c:\\somedir\\filename.jpg");

	//释放资源
	delete pImg;
	*/

	_nmsp2::ImageOS* pimgos_windows = new _nmsp2::ImageOS_Windows(); //针对Windows操作系统
	_nmsp2::ImageFormat* pimg_png = new _nmsp2::Image_png(pimgos_windows); //运行时把图像文件格式png和操作系统windows动态组合到一起。
	pimg_png->parsefile("c:\\somedir\\filename.jpg");

	//释放资源
	delete pimg_png;
	delete pimgos_windows;
	
	return 0;
}

// 运行程序: Ctrl + F5 或调试 >“开始执行(不调试)”菜单
// 调试程序: F5 或调试 >“开始调试”菜单

// 入门使用技巧: 
//   1. 使用解决方案资源管理器窗口添加/管理文件
//   2. 使用团队资源管理器窗口连接到源代码管理
//   3. 使用输出窗口查看生成输出和其他消息
//   4. 使用错误列表窗口查看错误
//   5. 转到“项目”>“添加新项”以创建新的代码文件，或转到“项目”>“添加现有项”以将现有代码文件添加到项目
//   6. 将来，若要再次打开此项目，请转到“文件”>“打开”>“项目”并选择 .sln 文件

